/*
 *Copyright (c) [2019-2020]  C2comm, Inc.  All rights reserved.
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; If not, see <https://www.gnu.org/licenses/>
 */

/*
 *Vendor: C2comm
 *Version: 1.0
 *Filename: PcfEventSend.v
 *Target Device: Altera
 *Author : 刘晓骏
*/

module PcfEventSend(
    input  wire         SYS2CORE_clk,
    input  wire         SYS2CORE_rst_n,
    
    input  wire [ 47:0] G_device_clk,
    input  wire [ 42:0] G_current_state,
    
    input  wire         G_pcf_des_wr,
    input  wire [ 90:0] G_pcf_des,
    
    output reg          CM2OPPM_pcf_tx_cb_wr,
    output reg  [ 63:0] CM2OPPM_pcf_tx_cb,
    input  wire         CM2OPPM_pcf_tx_cb_ready,
    
    output wire [298:0] CORE2MON_cm_state
);
/*//////////////////////////////////////////////////////////
                    中间变量声明区域
*///////////////////////////////////////////////////////////
//本模块中所有中间变量(wire/reg/parameter)在此集中声明
//缓存输入的G_pcf_des的FIFO信号
reg         ptcfifo_wrreq;
reg  [63:0] ptcfifo_wdata;
 
reg         ptcfifo_rdreq;
wire [63:0] ptcfifo_rdata;
wire [ 5:0] ptcfifo_usedw;
wire        ptcfifo_empty;
wire        ptcfifo_full;


reg         direct_des_wr;
wire [63:0] direct_des;
wire        direct_des_ready;

wire        directbuf_des_wrreq;
wire [63:0] directbuf_des;
reg         directbuf_des_wrack;


reg         delay_pcf_des_wr;
wire [63:0] delay_pcf_des;
wire        delay_pcf_des_ready;

reg         delayfifo_rdreq;
wire [63:0] delayfifo_rdata;
wire [ 5:0] delayfifo_usedw;
wire        delayfifo_empty;
wire        delayfifo_full;


wire        complete_pcf_des_wr;
wire [63:0] complete_pcf_des;
wire        complete_pcf_des_ready;

wire        completebuf_des_wrreq;
wire [63:0] completebuf_des;
reg         completebuf_des_wrack;

localparam CM_INTEGRATE  = 6'b000001,
           CM_UNSYNC     = 6'b000010,
           CM_CA_ENABLED = 6'b000100,
           CM_WAIT_4_IN  = 6'b001000,
           CM_SYNC       = 6'b010000,
           CM_STABLE     = 6'b100000;
           
localparam PCF_CS        = 2'd0,
           PCF_CA        = 2'd1,
           PCF_IN        = 2'd2;
/*//////////////////////////////////////////////////////////
                    状态信号处理
*///////////////////////////////////////////////////////////
assign CORE2MON_cm_state = {191'b0,CM2OPPM_pcf_tx_cb_wr,CM2OPPM_pcf_tx_cb,43'b0};


always @* begin  
    if(((G_pcf_des[17:16] == PCF_CS) && (G_current_state[42:37] == CM_UNSYNC)) || 
       ((G_pcf_des[17:16] == PCF_CA) && (G_current_state[42:37] == CM_CA_ENABLED)) || 
       ((G_pcf_des[17:16] == PCF_CA) && (G_current_state[42:37] == CM_UNSYNC) && (G_pcf_des[39] == 1'b1)) || 
       ((G_pcf_des[17:16] == PCF_IN) && (G_current_state[42:37] == CM_INTEGRATE)) || 
       ((G_pcf_des[17:16] == PCF_IN) && (G_current_state[42:37] == CM_UNSYNC)) || 
       ((G_pcf_des[17:16] == PCF_IN) && (G_current_state[42:37] == CM_WAIT_4_IN)) || 
       ((G_pcf_des[17:16] == PCF_IN) && (G_current_state[42:37] == CM_SYNC)) || 
       ((G_pcf_des[17:16] == PCF_IN) && (G_current_state[42:37] == CM_STABLE)))
        ptcfifo_wrreq = G_pcf_des_wr;
    else 
        ptcfifo_wrreq = 1'b0;
end

always @* begin
    ptcfifo_wdata = {G_pcf_des[90:43],
                     G_pcf_des[17:16],
                     G_pcf_des[15: 8],
                     G_pcf_des[ 7: 2]};
end



//时刻检测(PitDetect)
assign direct_des    = ptcfifo_rdata;
assign delay_pcf_des = ptcfifo_rdata;

always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        ptcfifo_rdreq   <= 1'b0;
        direct_des_wr    <= 1'b0;
        delay_pcf_des_wr <= 1'b0;
    end
    else begin
        if((ptcfifo_empty == 1'b0) && (ptcfifo_rdreq == 1'b0)) begin//fifo有数据且未被读出
            if(ptcfifo_rdata[63:16] <= G_device_clk) begin
           
                ptcfifo_rdreq   <= direct_des_ready;
                direct_des_wr    <= direct_des_ready;
                delay_pcf_des_wr <= 1'b0;
            end
            else begin
          
                ptcfifo_rdreq   <= delay_pcf_des_ready;
                direct_des_wr    <= 1'b0;
                delay_pcf_des_wr <= delay_pcf_des_ready;
            end
            
        end
        else begin
            ptcfifo_rdreq       <= 1'b0;
            direct_des_wr    <= 1'b0;
            delay_pcf_des_wr <= 1'b0;
        end
    end
end


/*//////////////////////////////////////////////////////////
        派发延迟功能(DispatchDelay)
*///////////////////////////////////////////////////////////
/*
由于输入的pcf_des在PitDelay模块已经经过延时的排序
而在该模块进行的延时都是固定的cm_dispatch_delay
因此，本模块的延时没有额外的排序需求，直接缓存到FIFO中按照顺序判断即可
*/
assign delay_pcf_des_ready = (delayfifo_usedw<6'd60);

assign complete_pcf_des_wr = delayfifo_rdreq;
assign complete_pcf_des    = delayfifo_rdata;

always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        delayfifo_rdreq <= 1'b0;
    end
    else begin
        if((complete_pcf_des_ready == 1'b1) &&
           (delayfifo_empty == 1'b0) &&
           (delayfifo_rdreq == 1'b0) && 
           (delayfifo_rdata[63:16] <= G_device_clk))begin
        
            delayfifo_rdreq <= 1'b1;
        end
        else begin
            delayfifo_rdreq <= 1'b0;
        end
    end
end
/*//////////////////////////////////////////////////////////
        派发PCF选择功能(DispatchPCFPick)
*///////////////////////////////////////////////////////////
always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        CM2OPPM_pcf_tx_cb_wr  <= 1'b0;
        directbuf_des_wrack   <= 1'b0;
        completebuf_des_wrack <= 1'b0;
        CM2OPPM_pcf_tx_cb     <= 64'b0;//add by lxj 20200514
    end
    else begin
        if((directbuf_des_wrreq == 1'b1) && (CM2OPPM_pcf_tx_cb_ready == 1'b1)) begin
            CM2OPPM_pcf_tx_cb_wr  <= 1'b1;
            CM2OPPM_pcf_tx_cb     <= directbuf_des;
            directbuf_des_wrack   <= 1'b1;
            completebuf_des_wrack <= 1'b0;
        end
        else if((completebuf_des_wrreq == 1'b1) && (CM2OPPM_pcf_tx_cb_ready == 1'b1)) begin
            CM2OPPM_pcf_tx_cb_wr  <= 1'b1;
            CM2OPPM_pcf_tx_cb     <= completebuf_des;
            directbuf_des_wrack   <= 1'b0;
            completebuf_des_wrack <= 1'b1;
        end
        else begin
            CM2OPPM_pcf_tx_cb_wr  <= 1'b0;
            directbuf_des_wrack   <= 1'b0;
            completebuf_des_wrack <= 1'b0;
        end
    end
end
/*//////////////////////////////////////////////////////////
                   IP调用区域
*///////////////////////////////////////////////////////////
//本模块调用的所有IP在该区域实例化
//例如fifo/ram/grant之类的IP....
PcfTxcbFifo PcfTxcbFifo(
    .clock (SYS2CORE_clk),
    .aclr  (~SYS2CORE_rst_n),
    
    .wrreq (ptcfifo_wrreq),
    .data  (ptcfifo_wdata),
    .rdreq (ptcfifo_rdreq),

    .q     (ptcfifo_rdata),
    .usedw (ptcfifo_usedw),
    .empty (ptcfifo_empty),
    .full  (ptcfifo_full)
);

InportBuffer #(
    .DWIDTH(64)
)DirectBuffer(
    .clk(SYS2CORE_clk),
    .rst_n(SYS2CORE_rst_n),

    .idata_valid(direct_des_wr),
    .idata(direct_des),
    .idata_ready(direct_des_ready),

    .odata_wrreq(directbuf_des_wrreq),
    .odata(directbuf_des),
    .odata_wrack(directbuf_des_wrack)
); 

PcfTxcbFifo DelayFifo(
    .clock (SYS2CORE_clk),
    .aclr  (~SYS2CORE_rst_n),
    
    .wrreq (delay_pcf_des_wr),
    .data  (delay_pcf_des),
    .rdreq (delayfifo_rdreq),

    .q     (delayfifo_rdata),
    .usedw (delayfifo_usedw),
    .empty (delayfifo_empty),
    .full  (delayfifo_full)
);

InportBuffer #(
    .DWIDTH(64)
)CompleteBuffer(
    .clk(SYS2CORE_clk),
    .rst_n(SYS2CORE_rst_n),

    .idata_valid(complete_pcf_des_wr),
    .idata(complete_pcf_des),
    .idata_ready(complete_pcf_des_ready),

    .odata_wrreq(completebuf_des_wrreq),
    .odata(completebuf_des),
    .odata_wrack(completebuf_des_wrack)
); 
endmodule
/*
PcfEventSend PcfEventSend_inst(
    .SYS2CORE_clk(),
    .SYS2CORE_rst_n(),

    .G_device_clk(),
    .G_current_state(),
    
    .CONF2CORE_cm_static_conf(),

    .G_pcf_des_wr(),
    .G_pcf_des(),

    .CM2OPPM_pcf_tx_cb_wr(),
    .CM2OPPM_pcf_tx_cb(),
    .CM2OPPM_pcf_tx_cb_ready(),
    .CORE2MON_cm_state()
);
*/